﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace server.app
{
    public sealed class StateManager : comm.world.BObject
    {
        Dictionary<string, State> _stateDic = new Dictionary<string, State>();

        World _world = null;
        Object _obj = null;

        public Action<string> OnAddStateCallback = null;
        public Action<string> OnRemoveStateCallback = null;

        public StateManager(World world, Object obj)
        {
            _world = world;
            _obj = obj;
        }

        public void AddState(string stateId, int dur = -1, DateTime? beginTime = null)
        {
            lock (this)
            {
                if (!_stateDic.ContainsKey(stateId))
                {
                    var state = _world.DataManager.CreateState(_obj, stateId, beginTime.HasValue ? beginTime.Value : DateTime.Now, dur);
                    _stateDic.Add(stateId, state);
                    if (OnAddStateCallback != null)
                    {
                        OnAddStateCallback(stateId);
                    }
                }
                else
                {
                    _stateDic[stateId].AddDur(dur);
                }
            }
        }
        public void AddStateNotExists(string stateId, int dur, DateTime? beginTime = null)
        {
            lock (this)
            {
                if (!_stateDic.ContainsKey(stateId))
                {
                    var state = _world.DataManager.CreateState(_obj, stateId, beginTime.HasValue ? beginTime.Value : DateTime.Now, dur);
                    _stateDic.Add(stateId, state);
                    if (OnAddStateCallback != null)
                    {
                        OnAddStateCallback(stateId);
                    }
                }
            }
        }
        public void RemoveState(string stateId)
        {
            lock (this)
            {
                if (_stateDic.ContainsKey(stateId))
                {
                    if (OnRemoveStateCallback != null)
                    {
                        OnRemoveStateCallback(stateId);
                    }
                    _stateDic[stateId].Remove();
                    _stateDic.Remove(stateId);
                }
            }
        }
        public State[] GetAllState()
        {
            lock (this)
            {
                var list = new List<State>();
                foreach (var state in _stateDic.Values)
                {
                    list.Add(state);
                }
                return list.ToArray();
            }
        }
        public State GetState(string stateId)
        {
            State state = null;
            _stateDic.TryGetValue(stateId, out state);
            return state;
        }
        public bool StateExists(string stateId)
        {
            return _stateDic.ContainsKey(stateId);
        }
        public comm.objst.State[] GetAllStateInfo(bool? save = null)
        {
            var list = new List<comm.objst.State>();
            var states = _world.DefineFile.GetAllState(save);
            foreach (var stateId in states)
            {
                var state = GetState(stateId);
                if (state != null)
                {
                    list.Add(state.GetStateInfo());
                }
            }
            return list.ToArray();
        }

        protected override void OnUpdate(comm.TimeStat timeStat)
        {
            lock (this)
            {
                var stopList = new List<string>();
                foreach (var state in _stateDic.Values)
                {
                    state.Update(timeStat);
                    if (state.GetOverTime().TotalMilliseconds <= 0)
                    {
                        stopList.Add(state.StateId);
                    }
                }
                foreach (var stateId in stopList)
                {
                    RemoveState(stateId);
                }
            }
        }
    }

    public abstract class State : comm.world.BObject
    {
        public string StateId { get; private set; }
        public DateTime BeginTime { get; private set; }
        public int Dur { get; private set; }
        protected Object Object { get; private set; }

        World _world = null;
        comm.objst.DState _dState = null;

        public State(World world, Object obj, string stateId, DateTime beginTime, int dur)
        {
            Object = obj;
            StateId = stateId;
            BeginTime = beginTime;
            Dur = dur == -1 ? dur : Math.Max(0, dur);

            _world = world;
            _dState = _world.DefineFile.GetState(stateId);
        }

        protected override void OnUpdate(comm.TimeStat timeStat)
        {
        }
        protected virtual void OnRemove()
        {
        }

        public void Remove()
        {
            OnRemove();
        }
        public void AddDur(int dur)
        {
            if (dur == -1)
            {
                Dur = dur;
            }
            else
            {
                Dur += Math.Max(0, dur);
            }
        }
        public TimeSpan GetOverTime()
        {
            if (Dur == -1)
            {
                return new TimeSpan(365, 0, 0, 0);
            }
            return new TimeSpan(Dur * 10000 - (DateTime.Now.Ticks - BeginTime.Ticks));
        }
        public comm.objst.State GetStateInfo()
        {
            return new comm.objst.State
            {
                StateId = StateId,
                BeginTime = BeginTime,
                Dur = Dur
            };
        }
    }
}
